/*
 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.impl.orb;

import java.applet.Applet;

import java.io.IOException;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;

import java.util.Set;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Map;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Collection;
import java.util.Collections;
import java.util.StringTokenizer;
import java.util.Enumeration;
import java.util.WeakHashMap;

import java.net.InetAddress;

import java.security.PrivilegedAction;
import java.security.AccessController;

import javax.rmi.CORBA.Util;
import javax.rmi.CORBA.ValueHandler;

import org.omg.CORBA.Context;
import org.omg.CORBA.ContextList;
import org.omg.CORBA.Environment;
import org.omg.CORBA.ExceptionList;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CORBA.NVList;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.NamedValue;
import org.omg.CORBA.Request;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.Any;
import org.omg.CORBA.StructMember;
import org.omg.CORBA.UnionMember;
import org.omg.CORBA.ValueMember;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.MARSHAL;

import org.omg.CORBA.portable.ValueFactory;

import org.omg.CORBA.ORBPackage.InvalidName;

import com.sun.org.omg.SendingContext.CodeBase;

import com.sun.corba.se.pept.broker.Broker;
import com.sun.corba.se.pept.protocol.ClientInvocationInfo;
import com.sun.corba.se.pept.transport.ContactInfo;
import com.sun.corba.se.pept.transport.ConnectionCache;
import com.sun.corba.se.pept.transport.TransportManager;

import com.sun.corba.se.spi.ior.IOR;
import com.sun.corba.se.spi.ior.IdentifiableFactoryFinder;
import com.sun.corba.se.spi.ior.TaggedComponentFactoryFinder;
import com.sun.corba.se.spi.ior.IORFactories;
import com.sun.corba.se.spi.ior.ObjectKey;
import com.sun.corba.se.spi.ior.ObjectKeyFactory;
import com.sun.corba.se.spi.ior.iiop.IIOPFactories;
import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
import com.sun.corba.se.spi.oa.OAInvocationInfo;
import com.sun.corba.se.spi.oa.ObjectAdapterFactory;
import com.sun.corba.se.spi.orb.DataCollector;
import com.sun.corba.se.spi.orb.Operation;
import com.sun.corba.se.spi.orb.ORBData;
import com.sun.corba.se.spi.orb.ORBConfigurator;
import com.sun.corba.se.spi.orb.ParserImplBase;
import com.sun.corba.se.spi.orb.PropertyParser;
import com.sun.corba.se.spi.orb.OperationFactory;
import com.sun.corba.se.spi.orb.ORBVersion;
import com.sun.corba.se.spi.orb.ORBVersionFactory;
import com.sun.corba.se.spi.orbutil.closure.ClosureFactory;
import com.sun.corba.se.spi.orbutil.threadpool.ThreadPoolManager;
import com.sun.corba.se.spi.protocol.ClientDelegateFactory;
import com.sun.corba.se.spi.protocol.RequestDispatcherRegistry;
import com.sun.corba.se.spi.protocol.CorbaServerRequestDispatcher;
import com.sun.corba.se.spi.protocol.RequestDispatcherDefault;
import com.sun.corba.se.spi.protocol.PIHandler;
import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
import com.sun.corba.se.spi.protocol.ForwardException;
import com.sun.corba.se.spi.resolver.Resolver;
import com.sun.corba.se.spi.resolver.LocalResolver;
import com.sun.corba.se.spi.orb.StringPair;
import com.sun.corba.se.spi.orb.StringPair;
import com.sun.corba.se.spi.transport.CorbaContactInfoListFactory;
import com.sun.corba.se.spi.transport.CorbaTransportManager;
import com.sun.corba.se.spi.legacy.connection.LegacyServerSocketManager;
import com.sun.corba.se.spi.copyobject.CopierManager;
import com.sun.corba.se.spi.presentation.rmi.PresentationDefaults;
import com.sun.corba.se.spi.presentation.rmi.PresentationManager;
import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
import com.sun.corba.se.spi.servicecontext.ServiceContextRegistry;

import com.sun.corba.se.impl.corba.TypeCodeFactory;
import com.sun.corba.se.impl.corba.TypeCodeImpl;
import com.sun.corba.se.impl.corba.NVListImpl;
import com.sun.corba.se.impl.corba.ExceptionListImpl;
import com.sun.corba.se.impl.corba.ContextListImpl;
import com.sun.corba.se.impl.corba.NamedValueImpl;
import com.sun.corba.se.impl.corba.EnvironmentImpl;
import com.sun.corba.se.impl.corba.AsynchInvoke;
import com.sun.corba.se.impl.corba.AnyImpl;
import com.sun.corba.se.impl.corba.RequestImpl;
import com.sun.corba.se.impl.dynamicany.DynAnyFactoryImpl;
import com.sun.corba.se.impl.encoding.EncapsOutputStream;
import com.sun.corba.se.impl.encoding.CachedCodeBase;
import com.sun.corba.se.impl.interceptors.PIHandlerImpl;
import com.sun.corba.se.impl.interceptors.PINoOpHandlerImpl;
import com.sun.corba.se.impl.ior.TaggedComponentFactoryFinderImpl;
import com.sun.corba.se.impl.ior.TaggedProfileFactoryFinderImpl;
import com.sun.corba.se.impl.ior.TaggedProfileTemplateFactoryFinderImpl;
import com.sun.corba.se.impl.oa.toa.TOAFactory;
import com.sun.corba.se.impl.oa.poa.BadServerIdHandler;
import com.sun.corba.se.impl.oa.poa.DelegateImpl;
import com.sun.corba.se.impl.oa.poa.POAFactory;
import com.sun.corba.se.impl.orbutil.ORBConstants;
import com.sun.corba.se.impl.orbutil.ORBUtility;
import com.sun.corba.se.impl.orbutil.StackImpl;
import com.sun.corba.se.impl.orbutil.threadpool.ThreadPoolImpl;
import com.sun.corba.se.impl.orbutil.threadpool.ThreadPoolManagerImpl;
import com.sun.corba.se.impl.protocol.RequestDispatcherRegistryImpl;
import com.sun.corba.se.impl.protocol.CorbaInvocationInfo;
import com.sun.corba.se.impl.transport.CorbaTransportManagerImpl;
import com.sun.corba.se.impl.legacy.connection.LegacyServerSocketManagerImpl;
import com.sun.corba.se.impl.util.Utility;
import com.sun.corba.se.impl.logging.ORBUtilSystemException;
import com.sun.corba.se.impl.copyobject.CopierManagerImpl;
import com.sun.corba.se.impl.presentation.rmi.PresentationManagerImpl;

/**
 * The JavaIDL ORB implementation.
 */
public class ORBImpl extends com.sun.corba.se.spi.orb.ORB {

  protected TransportManager transportManager;
  protected LegacyServerSocketManager legacyServerSocketManager;

  private ThreadLocal OAInvocationInfoStack;

  private ThreadLocal clientInvocationInfoStack;

  // pure java orb, caching the servant IOR per ORB
  private static IOR codeBaseIOR;

  // Vector holding deferred Requests
  private Vector dynamicRequests;
  private SynchVariable svResponseReceived;

  private java.lang.Object runObj = new java.lang.Object();
  private java.lang.Object shutdownObj = new java.lang.Object();
  private java.lang.Object waitForCompletionObj = new java.lang.Object();
  private static final byte STATUS_OPERATING = 1;
  private static final byte STATUS_SHUTTING_DOWN = 2;
  private static final byte STATUS_SHUTDOWN = 3;
  private static final byte STATUS_DESTROYED = 4;
  private byte status = STATUS_OPERATING;

  // XXX Should we move invocation tracking to the first level server dispatcher?
  private java.lang.Object invocationObj = new java.lang.Object();
  private int numInvocations = 0;

  // thread local variable to store a boolean to detect deadlock in
  // ORB.shutdown(true).
  private ThreadLocal isProcessingInvocation = new ThreadLocal() {
    protected java.lang.Object initialValue() {
      return Boolean.FALSE;
    }
  };

  // This map is caching TypeCodes created for a certain class (key)
  // and is used in Util.writeAny()
  private Map typeCodeForClassMap;

  // Cache to hold ValueFactories (Helper classes) keyed on repository ids
  private Hashtable valueFactoryCache = new Hashtable();

  // thread local variable to store the current ORB version.
  // default ORB version is the version of ORB with correct Rep-id
  // changes
  private ThreadLocal orbVersionThreadLocal;

  private RequestDispatcherRegistry requestDispatcherRegistry;

  private CopierManager copierManager;

  private int transientServerId;

  private ServiceContextRegistry serviceContextRegistry;

  // Needed here to implement connect/disconnect
  private TOAFactory toaFactory;

  // Needed here for set_delegate
  private POAFactory poaFactory;

  // The interceptor handler, which provides portable interceptor services for
  // subcontracts and object adapters.
  private PIHandler pihandler;

  private ORBData configData;

  private BadServerIdHandler badServerIdHandler;

  private ClientDelegateFactory clientDelegateFactory;

  private CorbaContactInfoListFactory corbaContactInfoListFactory;

  // All access to resolver, localResolver, and urlOperation must be protected using
  // resolverLock.  Do not hold the ORBImpl lock while accessing
  // resolver, or deadlocks may occur.
  // Note that we now have separate locks for each resolver type.  This is due
  // to bug 6980681 and 6238477, which was caused by a deadlock while resolving a
  // corbaname: URL that contained a reference to the same ORB as the
  // ORB making the call to string_to_object.  This caused a deadlock between the
  // client thread holding the single lock for access to the urlOperation,
  // and the server thread handling the client is_a request waiting on the
  // same lock to access the localResolver.


  // Used for resolver_initial_references and list_initial_services
  private Resolver resolver;

  // Used for register_initial_references
  private LocalResolver localResolver;

  // Converts strings to object references for resolvers and string_to_object
  private Operation urlOperation;
  private final Object urlOperationLock = new java.lang.Object();

  private CorbaServerRequestDispatcher insNamingDelegate;

  // resolverLock must be used for all access to either resolver or
  // localResolver, since it is possible for the resolver to indirectly
  // refer to the localResolver.  Also used to protect access to
  // insNamingDelegate.
  private final Object resolverLock = new Object();

  private TaggedComponentFactoryFinder taggedComponentFactoryFinder;

  private IdentifiableFactoryFinder taggedProfileFactoryFinder;

  private IdentifiableFactoryFinder taggedProfileTemplateFactoryFinder;

  private ObjectKeyFactory objectKeyFactory;

  private boolean orbOwnsThreadPoolManager = false;

  private ThreadPoolManager threadpoolMgr;

  private void dprint(String msg) {
    ORBUtility.dprint(this, msg);
  }

  ////////////////////////////////////////////////////
  //
  // NOTE:
  //
  // Methods that are synchronized MUST stay synchronized.
  //
  // Methods that are NOT synchronized must stay that way to avoid deadlock.
  //
  //
  // REVISIT:
  //
  // checkShutDownState - lock on different object - and normalize usage.
  // starting/FinishDispatch and Shutdown
  //

  public ORBData getORBData() {
    return configData;
  }

  public PIHandler getPIHandler() {
    return pihandler;
  }

  /**
   * Create a new ORB. Should be followed by the appropriate
   * set_parameters() call.
   */
  public ORBImpl() {
    // All initialization is done through set_parameters().
  }

  public ORBVersion getORBVersion() {
    synchronized (this) {
      checkShutdownState();
    }
    return (ORBVersion) (orbVersionThreadLocal.get());
  }

  public void setORBVersion(ORBVersion verObj) {
    synchronized (this) {
      checkShutdownState();
    }
    orbVersionThreadLocal.set(verObj);
  }

  /****************************************************************************
   * The following methods are ORB initialization
   ****************************************************************************/

  // preInit initializes all non-pluggable ORB data that is independent
  // of the property parsing.
  private void preInit(String[] params, Properties props) {
    // Before ORBConfiguration we need to set a PINoOpHandlerImpl,
    // because PersisentServer Initialization inside configurator will
    // invoke orb.resolve_initial_references( ) which will result in a
    // check on piHandler to invoke Interceptors. We do not want any
    // Interceptors to be invoked before the complete ORB initialization.
    // piHandler will be replaced by a real PIHandler implementation at the
    // end of this method.
    pihandler = new PINoOpHandlerImpl();

    // This is the unique id of this server (JVM). Multiple incarnations
    // of this server will get different ids.
    // Compute transientServerId = milliseconds since Jan 1, 1970
    // Note: transientServerId will wrap in about 2^32 / 86400000 = 49.7 days.
    // If two ORBS are started at the same time then there is a possibility
    // of having the same transientServerId. This may result in collision
    // and may be a problem in ior.isLocal() check to see if the object
    // belongs to the current ORB. This problem is taken care of by checking
    // to see if the IOR port matches ORB server port in legacyIsLocalServerPort()
    // method.
    //
    // XXX need to move server ID to a string for CORBA 3.0.  At that point,
    // make this more unique (possibly use java.rmi.server.UID).
    transientServerId = (int) System.currentTimeMillis();

    orbVersionThreadLocal = new ThreadLocal() {
      protected java.lang.Object initialValue() {
        // set default to version of the ORB with correct Rep-ids
        return ORBVersionFactory.getORBVersion();
      }
    };

    requestDispatcherRegistry = new RequestDispatcherRegistryImpl(
        this, ORBConstants.DEFAULT_SCID);
    copierManager = new CopierManagerImpl(this);

    taggedComponentFactoryFinder =
        new TaggedComponentFactoryFinderImpl(this);
    taggedProfileFactoryFinder =
        new TaggedProfileFactoryFinderImpl(this);
    taggedProfileTemplateFactoryFinder =
        new TaggedProfileTemplateFactoryFinderImpl(this);

    dynamicRequests = new Vector();
    svResponseReceived = new SynchVariable();

    OAInvocationInfoStack =
        new ThreadLocal() {
          protected java.lang.Object initialValue() {
            return new StackImpl();
          }
        };

    clientInvocationInfoStack =
        new ThreadLocal() {
          protected java.lang.Object initialValue() {
            return new StackImpl();
          }
        };

    serviceContextRegistry = new ServiceContextRegistry(this);
  }

  protected void setDebugFlags(String[] args) {
    for (int ctr = 0; ctr < args.length; ctr++) {
      String token = args[ctr];

      // If there is a public boolean data member in this class
      // named token + "DebugFlag", set it to true.
      try {
        Field fld = this.getClass().getField(token + "DebugFlag");
        int mod = fld.getModifiers();
        if (Modifier.isPublic(mod) && !Modifier.isStatic(mod)) {
          if (fld.getType() == boolean.class) {
            fld.setBoolean(this, true);
          }
        }
      } catch (Exception exc) {
        // ignore it XXX log this as info
      }
    }
  }

  // Class that defines a parser that gets the name of the
  // ORBConfigurator class.
  private static class ConfigParser extends ParserImplBase {

    // The default here is the ORBConfiguratorImpl that we define,
    // but this can be replaced.
    public Class configurator = ORBConfiguratorImpl.class;

    public PropertyParser makeParser() {
      PropertyParser parser = new PropertyParser();
      parser.add(ORBConstants.SUN_PREFIX + "ORBConfigurator",
          OperationFactory.classAction(), "configurator");
      return parser;
    }
  }

  private void postInit(String[] params, DataCollector dataCollector) {
    // First, create the standard ORB config data.
    // This must be initialized before the ORBConfigurator
    // is executed.
    configData = new ORBDataParserImpl(this, dataCollector);

    // Set the debug flags early so they can be used by other
    // parts of the initialization.
    setDebugFlags(configData.getORBDebugFlags());

    // REVISIT: this should go away after more transport init cleanup
    // and going to ORT based ORBD.
    getTransportManager();
    getLegacyServerSocketManager();

    // Create a parser to get the configured ORBConfigurator.
    ConfigParser parser = new ConfigParser();
    parser.init(dataCollector);

    ORBConfigurator configurator = null;
    try {
      configurator =
          (ORBConfigurator) (parser.configurator.newInstance());
    } catch (Exception iexc) {
      throw wrapper.badOrbConfigurator(iexc, parser.configurator.getName());
    }

    // Finally, run the configurator.  Note that the default implementation allows
    // other configurators with their own parsers to run,
    // using the same DataCollector.
    try {
      configurator.configure(dataCollector, this);
    } catch (Exception exc) {
      throw wrapper.orbConfiguratorError(exc);
    }

    // Last of all, create the PIHandler and run the ORB initializers.
    pihandler = new PIHandlerImpl(this, params);
    pihandler.initialize();

    // Initialize the thread manager pool and byte buffer pool
    // so they may be initialized & accessed without synchronization
    getThreadPoolManager();

    super.getByteBufferPool();
  }

  private synchronized POAFactory getPOAFactory() {
    if (poaFactory == null) {
      poaFactory = (POAFactory) requestDispatcherRegistry.getObjectAdapterFactory(
          ORBConstants.TRANSIENT_SCID);
    }

    return poaFactory;
  }

  private synchronized TOAFactory getTOAFactory() {
    if (toaFactory == null) {
      toaFactory = (TOAFactory) requestDispatcherRegistry.getObjectAdapterFactory(
          ORBConstants.TOA_SCID);
    }

    return toaFactory;
  }

  public void set_parameters(Properties props) {
    synchronized (this) {
      checkShutdownState();
    }
    preInit(null, props);
    DataCollector dataCollector =
        DataCollectorFactory.create(props, getLocalHostName());
    postInit(null, dataCollector);
  }

  protected void set_parameters(Applet app, Properties props) {
    preInit(null, props);
    DataCollector dataCollector =
        DataCollectorFactory.create(app, props, getLocalHostName());
    postInit(null, dataCollector);
  }

  protected void set_parameters(String[] params, Properties props) {
    preInit(params, props);
    DataCollector dataCollector =
        DataCollectorFactory.create(params, props, getLocalHostName());
    postInit(params, dataCollector);
  }

  /****************************************************************************
   * The following methods are standard public CORBA ORB APIs
   ****************************************************************************/

  public synchronized org.omg.CORBA.portable.OutputStream create_output_stream() {
    checkShutdownState();
    return sun.corba.OutputStreamFactory.newEncapsOutputStream(this);
  }

  /**
   * Get a Current pseudo-object.
   * The Current interface is used to manage thread-specific
   * information for use by the transactions, security and other
   * services. This method is deprecated,
   * and replaced by ORB.resolve_initial_references("NameOfCurrentObject");
   *
   * @return a Current pseudo-object.
   * @deprecated
   */
  public synchronized org.omg.CORBA.Current get_current() {
    checkShutdownState();

        /* _REVISIT_
           The implementation of get_current is not clear. How would
           ORB know whether the caller wants a Current for transactions
           or security ?? Or is it assumed that there is just one
           implementation for both ? If Current is thread-specific,
           then it should not be instantiated; so where does the
           ORB get a Current ?

           This should probably be deprecated. */

    throw wrapper.genericNoImpl();
  }

  /**
   * Create an NVList
   *
   * @param count size of list to create
   * @result NVList created
   * @see NVList
   */
  public synchronized NVList create_list(int count) {
    checkShutdownState();
    return new NVListImpl(this, count);
  }

  /**
   * Create an NVList corresponding to an OperationDef
   *
   * @param oper operation def to use to create list
   * @result NVList created
   * @see NVList
   */
  public synchronized NVList create_operation_list(org.omg.CORBA.Object oper) {
    checkShutdownState();
    throw wrapper.genericNoImpl();
  }

  /**
   * Create a NamedValue
   *
   * @result NamedValue created
   */
  public synchronized NamedValue create_named_value(String s, Any any, int flags) {
    checkShutdownState();
    return new NamedValueImpl(this, s, any, flags);
  }

  /**
   * Create an ExceptionList
   *
   * @result ExceptionList created
   */
  public synchronized org.omg.CORBA.ExceptionList create_exception_list() {
    checkShutdownState();
    return new ExceptionListImpl();
  }

  /**
   * Create a ContextList
   *
   * @result ContextList created
   */
  public synchronized org.omg.CORBA.ContextList create_context_list() {
    checkShutdownState();
    return new ContextListImpl(this);
  }

  /**
   * Get the default Context object
   *
   * @result the default Context object
   */
  public synchronized org.omg.CORBA.Context get_default_context() {
    checkShutdownState();
    throw wrapper.genericNoImpl();
  }

  /**
   * Create an Environment
   *
   * @result Environment created
   */
  public synchronized org.omg.CORBA.Environment create_environment() {
    checkShutdownState();
    return new EnvironmentImpl();
  }

  public synchronized void send_multiple_requests_oneway(Request[] req) {
    checkShutdownState();

    // Invoke the send_oneway on each new Request
    for (int i = 0; i < req.length; i++) {
      req[i].send_oneway();
    }
  }

  /**
   * Send multiple dynamic requests asynchronously.
   *
   * @param req an array of request objects.
   */
  public synchronized void send_multiple_requests_deferred(Request[] req) {
    checkShutdownState();

    // add the new Requests to pending dynamic Requests
    for (int i = 0; i < req.length; i++) {
      dynamicRequests.addElement(req[i]);
    }

    // Invoke the send_deferred on each new Request
    for (int i = 0; i < req.length; i++) {
      AsynchInvoke invokeObject = new AsynchInvoke(this,
          (com.sun.corba.se.impl.corba.RequestImpl) req[i], true);
      new Thread(invokeObject).start();
    }
  }

  /**
   * Find out if any of the deferred invocations have a response yet.
   */
  public synchronized boolean poll_next_response() {
    checkShutdownState();

    Request currRequest;

    // poll on each pending request
    Enumeration ve = dynamicRequests.elements();
    while (ve.hasMoreElements() == true) {
      currRequest = (Request) ve.nextElement();
      if (currRequest.poll_response() == true) {
        return true;
      }
    }
    return false;
  }

  /**
   * Get the next request that has gotten a response.
   *
   * @result the next request ready with a response.
   */
  public org.omg.CORBA.Request get_next_response()
      throws org.omg.CORBA.WrongTransaction {
    synchronized (this) {
      checkShutdownState();
    }

    while (true) {
      // check if there already is a response
      synchronized (dynamicRequests) {
        Enumeration elems = dynamicRequests.elements();
        while (elems.hasMoreElements()) {
          Request currRequest = (Request) elems.nextElement();
          if (currRequest.poll_response()) {
            // get the response for this successfully polled Request
            currRequest.get_response();
            dynamicRequests.removeElement(currRequest);
            return currRequest;
          }
        }
      }

      // wait for a response
      synchronized (this.svResponseReceived) {
        while (!this.svResponseReceived.value()) {
          try {
            this.svResponseReceived.wait();
          } catch (java.lang.InterruptedException ex) {
            // NO-OP
          }
        }
        // reinitialize the response flag
        this.svResponseReceived.reset();
      }
    }
  }

  /**
   * Notify response to ORB for get_next_response
   */
  public void notifyORB() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (this.svResponseReceived) {
      this.svResponseReceived.set();
      this.svResponseReceived.notify();
    }
  }

  /**
   * Convert an object ref to a string.
   *
   * @param obj The object to stringify.
   * @return A stringified object reference.
   */
  public synchronized String object_to_string(org.omg.CORBA.Object obj) {
    checkShutdownState();

    // Handle the null objref case
    if (obj == null) {
      IOR nullIOR = IORFactories.makeIOR(this);
      return nullIOR.stringify();
    }

    IOR ior = null;

    try {
      ior = ORBUtility.connectAndGetIOR(this, obj);
    } catch (BAD_PARAM bp) {
      // Throw MARSHAL instead if this is a LOCAL_OBJECT_NOT_ALLOWED error.
      if (bp.minor == ORBUtilSystemException.LOCAL_OBJECT_NOT_ALLOWED) {
        throw omgWrapper.notAnObjectImpl(bp);
      } else
      // Not a local object problem: just rethrow the exception.
      // Do not wrap and log this, since it was already logged at its
      // point of origin.
      {
        throw bp;
      }
    }

    return ior.stringify();
  }

  /**
   * Convert a stringified object reference to the object it represents.
   *
   * @param str The stringified object reference.
   * @return The unstringified object reference.
   */
  public org.omg.CORBA.Object string_to_object(String str) {
    Operation op;

    synchronized (this) {
      checkShutdownState();
      op = urlOperation;
    }

    if (str == null) {
      throw wrapper.nullParam();
    }

    synchronized (urlOperationLock) {
      org.omg.CORBA.Object obj = (org.omg.CORBA.Object) op.operate(str);
      return obj;
    }
  }

  // pure java orb support, moved this method from FVDCodeBaseImpl.
  // Note that we connect this if we have not already done so.
  public synchronized IOR getFVDCodeBaseIOR() {
    checkShutdownState();

    if (codeBaseIOR != null) // i.e. We are already connected to it
    {
      return codeBaseIOR;
    }

    // backward compatability 4365188
    CodeBase cb;

    ValueHandler vh = ORBUtility.createValueHandler();

    cb = (CodeBase) vh.getRunTimeCodeBase();
    return ORBUtility.connectAndGetIOR(this, cb);
  }

  /**
   * Get the TypeCode for a primitive type.
   *
   * @param tcKind the integer kind for the primitive type
   * @return the requested TypeCode
   */
  public synchronized TypeCode get_primitive_tc(TCKind tcKind) {
    checkShutdownState();
    return get_primitive_tc(tcKind.value());
  }

  /**
   * Create a TypeCode for a structure.
   *
   * @param id the logical id for the typecode.
   * @param name the name for the typecode.
   * @param members an array describing the members of the TypeCode.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_struct_tc(String id,
      String name,
      StructMember[] members) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_struct, id, name, members);
  }

  /**
   * Create a TypeCode for a union.
   *
   * @param id the logical id for the typecode.
   * @param name the name for the typecode.
   * @param discriminator_type the type of the union discriminator.
   * @param members an array describing the members of the TypeCode.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_union_tc(String id,
      String name,
      TypeCode discriminator_type,
      UnionMember[] members) {
    checkShutdownState();
    return new TypeCodeImpl(this,
        TCKind._tk_union,
        id,
        name,
        discriminator_type,
        members);
  }

  /**
   * Create a TypeCode for an enum.
   *
   * @param id the logical id for the typecode.
   * @param name the name for the typecode.
   * @param members an array describing the members of the TypeCode.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_enum_tc(String id,
      String name,
      String[] members) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_enum, id, name, members);
  }

  /**
   * Create a TypeCode for an alias.
   *
   * @param id the logical id for the typecode.
   * @param name the name for the typecode.
   * @param original_type the type this is an alias for.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_alias_tc(String id,
      String name,
      TypeCode original_type) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_alias, id, name, original_type);
  }

  /**
   * Create a TypeCode for an exception.
   *
   * @param id the logical id for the typecode.
   * @param name the name for the typecode.
   * @param members an array describing the members of the TypeCode.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_exception_tc(String id,
      String name,
      StructMember[] members) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_except, id, name, members);
  }

  /**
   * Create a TypeCode for an interface.
   *
   * @param id the logical id for the typecode.
   * @param name the name for the typecode.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_interface_tc(String id,
      String name) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_objref, id, name);
  }

  /**
   * Create a TypeCode for a string.
   *
   * @param bound the bound for the string.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_string_tc(int bound) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_string, bound);
  }

  /**
   * Create a TypeCode for a wide string.
   *
   * @param bound the bound for the string.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_wstring_tc(int bound) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_wstring, bound);
  }

  /**
   * Create a TypeCode for a sequence.
   *
   * @param bound the bound for the sequence.
   * @param element_type the type of elements of the sequence.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_sequence_tc(int bound,
      TypeCode element_type) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_sequence, bound, element_type);
  }


  /**
   * Create a recursive TypeCode in a sequence.
   *
   * @param bound the bound for the sequence.
   * @param offset the index to the enclosing TypeCode that is being referenced.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_recursive_sequence_tc(int bound,
      int offset) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_sequence, bound, offset);
  }


  /**
   * Create a TypeCode for an array.
   *
   * @param length the length of the array.
   * @param element_type the type of elements of the array.
   * @return the requested TypeCode.
   */
  public synchronized TypeCode create_array_tc(int length,
      TypeCode element_type) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_array, length, element_type);
  }


  public synchronized org.omg.CORBA.TypeCode create_native_tc(String id,
      String name) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_native, id, name);
  }

  public synchronized org.omg.CORBA.TypeCode create_abstract_interface_tc(
      String id,
      String name) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_abstract_interface, id, name);
  }

  public synchronized org.omg.CORBA.TypeCode create_fixed_tc(short digits, short scale) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_fixed, digits, scale);
  }

  public synchronized org.omg.CORBA.TypeCode create_value_tc(String id,
      String name,
      short type_modifier,
      TypeCode concrete_base,
      ValueMember[] members) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_value, id, name,
        type_modifier, concrete_base, members);
  }

  public synchronized org.omg.CORBA.TypeCode create_recursive_tc(String id) {
    checkShutdownState();
    return new TypeCodeImpl(this, id);
  }

  public synchronized org.omg.CORBA.TypeCode create_value_box_tc(String id,
      String name,
      TypeCode boxed_type) {
    checkShutdownState();
    return new TypeCodeImpl(this, TCKind._tk_value_box, id, name,
        boxed_type);
  }

  /**
   * Create a new Any
   *
   * @return the new Any created.
   */
  public synchronized Any create_any() {
    checkShutdownState();
    return new AnyImpl(this);
  }

  // TypeCodeFactory interface methods.
  // Keeping track of type codes by repository id.

  // Keeping a cache of TypeCodes associated with the class
  // they got created from in Util.writeAny().

  public synchronized void setTypeCodeForClass(Class c, TypeCodeImpl tci) {
    checkShutdownState();

    if (typeCodeForClassMap == null) {
      typeCodeForClassMap = Collections.synchronizedMap(
          new WeakHashMap(64));
    }
    // Store only one TypeCode per class.
    if (!typeCodeForClassMap.containsKey(c)) {
      typeCodeForClassMap.put(c, tci);
    }
  }

  public synchronized TypeCodeImpl getTypeCodeForClass(Class c) {
    checkShutdownState();

    if (typeCodeForClassMap == null) {
      return null;
    }
    return (TypeCodeImpl) typeCodeForClassMap.get(c);
  }

/****************************************************************************
 * The following methods deal with listing and resolving the initial
 * (bootstrap) object references such as "NameService".
 ****************************************************************************/

  /**
   * Get a list of the initially available CORBA services.
   * This does not work unless an ORBInitialHost is specified during
   * initialization (or unless there is an ORB running on the AppletHost)
   * since the localhostname
   * is inaccessible to applets. If a service properties URL was specified,
   * then it is used, otherwise the bootstrapping protocol is used.
   *
   * @return A list of the initial services available.
   */
  public String[] list_initial_services() {
    Resolver res;

    synchronized (this) {
      checkShutdownState();
      res = resolver;
    }

    synchronized (resolverLock) {
      java.util.Set keys = res.list();
      return (String[]) keys.toArray(new String[keys.size()]);
    }
  }

  /**
   * Resolve the stringified reference of one of the initially
   * available CORBA services.
   *
   * @param identifier The stringified object reference of the desired service.
   * @return An object reference for the desired service.
   * @throws InvalidName The supplied identifier is not associated with a known service.
   * @throws SystemException One of a fixed set of Corba system exceptions.
   */
  public org.omg.CORBA.Object resolve_initial_references(
      String identifier) throws InvalidName {
    Resolver res;

    synchronized (this) {
      checkShutdownState();
      res = resolver;
    }

    synchronized (resolverLock) {
      org.omg.CORBA.Object result = res.resolve(identifier);

      if (result == null) {
        throw new InvalidName();
      } else {
        return result;
      }
    }
  }

  /**
   * If this operation is called with an id, <code>"Y"</code>, and an
   * object, <code>YY</code>, then a subsequent call to
   * <code>ORB.resolve_initial_references( "Y" )</code> will
   * return object <code>YY</code>.
   *
   * @param id The ID by which the initial reference will be known.
   * @param obj The initial reference itself.
   * @throws InvalidName if this operation is called with an empty string id or this operation is
   * called with an id that is already registered, including the default names defined by OMG.
   * @throws BAD_PARAM if the obj parameter is null.
   */
  public void register_initial_reference(
      String id, org.omg.CORBA.Object obj) throws InvalidName {
    CorbaServerRequestDispatcher insnd;

    synchronized (this) {
      checkShutdownState();
    }

    if ((id == null) || (id.length() == 0)) {
      throw new InvalidName();
    }

    synchronized (this) {
      checkShutdownState();
    }

    synchronized (resolverLock) {
      insnd = insNamingDelegate;

      java.lang.Object obj2 = localResolver.resolve(id);
      if (obj2 != null) {
        throw new InvalidName(id + " already registered");
      }

      localResolver.register(id, ClosureFactory.makeConstant(obj));
    }

    synchronized (this) {
      if (StubAdapter.isStub(obj))
      // Make all remote object references available for INS.
      {
        requestDispatcherRegistry.registerServerRequestDispatcher(
            insnd, id);
      }
    }
  }

  /****************************************************************************
   * The following methods (introduced in POA / CORBA2.1) deal with
   * shutdown / single threading.
   ****************************************************************************/

  public void run() {
    synchronized (this) {
      checkShutdownState();
    }

    synchronized (runObj) {
      try {
        runObj.wait();
      } catch (InterruptedException ex) {
      }
    }
  }

  public void shutdown(boolean wait_for_completion) {
    boolean wait = false;

    synchronized (this) {
      checkShutdownState();

      // This is to avoid deadlock: don't allow a thread that is
      // processing a request to call shutdown( true ), because
      // the shutdown would block waiting for the request to complete,
      // while the request would block waiting for shutdown to complete.
      if (wait_for_completion &&
          isProcessingInvocation.get() == Boolean.TRUE) {
        throw omgWrapper.shutdownWaitForCompletionDeadlock();
      }

      if (status == STATUS_SHUTTING_DOWN) {
        if (wait_for_completion) {
          wait = true;
        } else {
          return;
        }
      }

      status = STATUS_SHUTTING_DOWN;
    }

    // Avoid more than one thread performing shutdown at a time.
    synchronized (shutdownObj) {
      // At this point, the ORB status is certainly STATUS_SHUTTING_DOWN.
      // If wait is true, another thread already called shutdown( true ),
      // and so we wait for completion
      if (wait) {
        while (true) {
          synchronized (this) {
            if (status == STATUS_SHUTDOWN) {
              break;
            }
          }

          try {
            shutdownObj.wait();
          } catch (InterruptedException exc) {
            // NOP: just loop and wait until state is changed
          }
        }
      } else {
        // perform the actual shutdown
        shutdownServants(wait_for_completion);

        if (wait_for_completion) {
          synchronized (waitForCompletionObj) {
            while (numInvocations > 0) {
              try {
                waitForCompletionObj.wait();
              } catch (InterruptedException ex) {
              }
            }
          }
        }

        synchronized (runObj) {
          runObj.notifyAll();
        }

        status = STATUS_SHUTDOWN;

        shutdownObj.notifyAll();
      }
    }
  }

  // Cause all ObjectAdapaterFactories to clean up all of their internal state, which
  // may include activated objects that have associated state and callbacks that must
  // complete in order to shutdown.  This will cause new request to be rejected.
  protected void shutdownServants(boolean wait_for_completion) {
    Set<ObjectAdapterFactory> oaset;
    synchronized (this) {
      oaset = new HashSet<>(requestDispatcherRegistry.getObjectAdapterFactories());
    }

    for (ObjectAdapterFactory oaf : oaset) {
      oaf.shutdown(wait_for_completion);
    }
  }

  // Note that the caller must hold the ORBImpl lock.
  public void checkShutdownState() {
    if (status == STATUS_DESTROYED) {
      throw wrapper.orbDestroyed();
    }

    if (status == STATUS_SHUTDOWN) {
      throw omgWrapper.badOperationAfterShutdown();
    }
  }

  public boolean isDuringDispatch() {
    synchronized (this) {
      checkShutdownState();
    }
    Boolean value = (Boolean) (isProcessingInvocation.get());
    return value.booleanValue();
  }

  public void startingDispatch() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (invocationObj) {
      isProcessingInvocation.set(Boolean.TRUE);
      numInvocations++;
    }
  }

  public void finishedDispatch() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (invocationObj) {
      numInvocations--;
      isProcessingInvocation.set(false);
      if (numInvocations == 0) {
        synchronized (waitForCompletionObj) {
          waitForCompletionObj.notifyAll();
        }
      } else if (numInvocations < 0) {
        throw wrapper.numInvocationsAlreadyZero(
            CompletionStatus.COMPLETED_YES);
      }
    }
  }

  /**
   * formal/99-10-07 p 159: "If destroy is called on an ORB that has
   * not been shut down, it will start the shutdown process and block until
   * the ORB has shut down before it destroys the ORB."
   */
  public void destroy() {
    boolean shutdownFirst = false;

    synchronized (this) {
      shutdownFirst = (status == STATUS_OPERATING);
    }

    if (shutdownFirst) {
      shutdown(true);
    }

    synchronized (this) {
      if (status < STATUS_DESTROYED) {
        getCorbaTransportManager().close();
        getPIHandler().destroyInterceptors();
        status = STATUS_DESTROYED;
      }
    }
    synchronized (threadPoolManagerAccessLock) {
      if (orbOwnsThreadPoolManager) {
        try {
          threadpoolMgr.close();
          threadpoolMgr = null;
        } catch (IOException exc) {
          wrapper.ioExceptionOnClose(exc);
        }
      }
    }

    try {
      monitoringManager.close();
      monitoringManager = null;
    } catch (IOException exc) {
      wrapper.ioExceptionOnClose(exc);
    }

    CachedCodeBase.cleanCache(this);
    try {
      pihandler.close();
    } catch (IOException exc) {
      wrapper.ioExceptionOnClose(exc);
    }

    super.destroy();

    badServerIdHandlerAccessLock = null;
    clientDelegateFactoryAccessorLock = null;
    corbaContactInfoListFactoryAccessLock = null;

    objectKeyFactoryAccessLock = null;
    legacyServerSocketManagerAccessLock = null;
    threadPoolManagerAccessLock = null;
    transportManager = null;
    legacyServerSocketManager = null;
    OAInvocationInfoStack = null;
    clientInvocationInfoStack = null;
    codeBaseIOR = null;
    dynamicRequests = null;
    svResponseReceived = null;
    runObj = null;
    shutdownObj = null;
    waitForCompletionObj = null;
    invocationObj = null;
    isProcessingInvocation = null;
    typeCodeForClassMap = null;
    valueFactoryCache = null;
    orbVersionThreadLocal = null;
    requestDispatcherRegistry = null;
    copierManager = null;
    toaFactory = null;
    poaFactory = null;
    pihandler = null;
    configData = null;
    badServerIdHandler = null;
    clientDelegateFactory = null;
    corbaContactInfoListFactory = null;
    resolver = null;
    localResolver = null;
    insNamingDelegate = null;
    urlOperation = null;
    taggedComponentFactoryFinder = null;
    taggedProfileFactoryFinder = null;
    taggedProfileTemplateFactoryFinder = null;
    objectKeyFactory = null;
  }

  /**
   * Registers a value factory for a particular repository ID.
   *
   * @param repositoryID the repository ID.
   * @param factory the factory.
   * @return the previously registered factory for the given repository ID, or null if no such
   * factory was previously registered.
   * @throws org.omg.CORBA.BAD_PARAM if the registration fails.
   **/
  public synchronized ValueFactory register_value_factory(String repositoryID,
      ValueFactory factory) {
    checkShutdownState();

    if ((repositoryID == null) || (factory == null)) {
      throw omgWrapper.unableRegisterValueFactory();
    }

    return (ValueFactory) valueFactoryCache.put(repositoryID, factory);
  }

  /**
   * Unregisters a value factory for a particular repository ID.
   *
   * @param repositoryID the repository ID.
   **/
  public synchronized void unregister_value_factory(String repositoryID) {
    checkShutdownState();

    if (valueFactoryCache.remove(repositoryID) == null) {
      throw wrapper.nullParam();
    }
  }

  /**
   * Finds and returns a value factory for the given repository ID.
   * The value factory returned was previously registered by a call to
   * {@link #register_value_factory} or is the default factory.
   *
   * @param repositoryID the repository ID.
   * @return the value factory.
   * @throws org.omg.CORBA.BAD_PARAM if unable to locate a factory.
   **/
  public synchronized ValueFactory lookup_value_factory(String repositoryID) {
    checkShutdownState();

    ValueFactory factory =
        (ValueFactory) valueFactoryCache.get(repositoryID);

    if (factory == null) {
      try {
        factory = Utility.getFactory(null, null, null, repositoryID);
      } catch (org.omg.CORBA.MARSHAL ex) {
        throw wrapper.unableFindValueFactory(ex);
      }
    }

    return factory;
  }

  public OAInvocationInfo peekInvocationInfo() {
    synchronized (this) {
      checkShutdownState();
    }
    StackImpl stack = (StackImpl) (OAInvocationInfoStack.get());
    return (OAInvocationInfo) (stack.peek());
  }

  public void pushInvocationInfo(OAInvocationInfo info) {
    synchronized (this) {
      checkShutdownState();
    }
    StackImpl stack = (StackImpl) (OAInvocationInfoStack.get());
    stack.push(info);
  }

  public OAInvocationInfo popInvocationInfo() {
    synchronized (this) {
      checkShutdownState();
    }
    StackImpl stack = (StackImpl) (OAInvocationInfoStack.get());
    return (OAInvocationInfo) (stack.pop());
  }

  /**
   * The bad server id handler is used by the Locator to
   * send back the location of a persistant server to the client.
   */

  private Object badServerIdHandlerAccessLock = new Object();

  public void initBadServerIdHandler() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (badServerIdHandlerAccessLock) {
      Class cls = configData.getBadServerIdHandler();
      if (cls != null) {
        try {
          Class[] params = new Class[]{org.omg.CORBA.ORB.class};
          java.lang.Object[] args = new java.lang.Object[]{this};
          Constructor cons = cls.getConstructor(params);
          badServerIdHandler =
              (BadServerIdHandler) cons.newInstance(args);
        } catch (Exception e) {
          throw wrapper.errorInitBadserveridhandler(e);
        }
      }
    }
  }

  public void setBadServerIdHandler(BadServerIdHandler handler) {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (badServerIdHandlerAccessLock) {
      badServerIdHandler = handler;
    }
  }

  public void handleBadServerId(ObjectKey okey) {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (badServerIdHandlerAccessLock) {
      if (badServerIdHandler == null) {
        throw wrapper.badServerId();
      } else {
        badServerIdHandler.handle(okey);
      }
    }
  }

  public synchronized org.omg.CORBA.Policy create_policy(int type,
      org.omg.CORBA.Any val) throws org.omg.CORBA.PolicyError {
    checkShutdownState();

    return pihandler.create_policy(type, val);
  }

  /**
   * This is the implementation of the public API used to connect
   * a servant-skeleton to the ORB.
   */
  public synchronized void connect(org.omg.CORBA.Object servant) {
    checkShutdownState();
    if (getTOAFactory() == null) {
      throw wrapper.noToa();
    }

    try {
      String codebase = javax.rmi.CORBA.Util.getCodebase(servant.getClass());
      getTOAFactory().getTOA(codebase).connect(servant);
    } catch (Exception ex) {
      throw wrapper.orbConnectError(ex);
    }
  }

  public synchronized void disconnect(org.omg.CORBA.Object obj) {
    checkShutdownState();
    if (getTOAFactory() == null) {
      throw wrapper.noToa();
    }

    try {
      getTOAFactory().getTOA().disconnect(obj);
    } catch (Exception ex) {
      throw wrapper.orbConnectError(ex);
    }
  }

  public int getTransientServerId() {
    synchronized (this) {
      checkShutdownState();
    }
    if (configData.getORBServerIdPropertySpecified()) {
      // ORBServerId is specified then use that value
      return configData.getPersistentServerId();
    }
    return transientServerId;
  }

  public RequestDispatcherRegistry getRequestDispatcherRegistry() {
    synchronized (this) {
      checkShutdownState();
    }
    return requestDispatcherRegistry;
  }

  public ServiceContextRegistry getServiceContextRegistry() {
    synchronized (this) {
      checkShutdownState();
    }
    return serviceContextRegistry;
  }

  // XXX All of the isLocalXXX checking needs to be revisited.
  // First of all, all three of these methods are called from
  // only one place in impl.ior.IORImpl.  Second, we have problems
  // both with multi-homed hosts and with multi-profile IORs.
  // A possible strategy: like the LocalClientRequestDispatcher, we need
  // to determine this more abstractly at the ContactInfo level.
  // This level should probably just get the CorbaContactInfoList from
  // the IOR, then iterator over ContactInfo.  If any ContactInfo is
  // local, the IOR is local, and we can pick one to create the
  // LocalClientRequestDispatcher as well.  Bottom line: this code needs to move.

  // XXX What about multi-homed host?
  public boolean isLocalHost(String hostName) {
    synchronized (this) {
      checkShutdownState();
    }
    return hostName.equals(configData.getORBServerHost()) ||
        hostName.equals(getLocalHostName());
  }

  public boolean isLocalServerId(int subcontractId, int serverId) {
    synchronized (this) {
      checkShutdownState();
    }
    if ((subcontractId < ORBConstants.FIRST_POA_SCID) ||
        (subcontractId > ORBConstants.MAX_POA_SCID)) {
      return serverId == getTransientServerId();
    }

    // XXX isTransient info should be stored in subcontract registry
    if (ORBConstants.isTransient(subcontractId)) {
      return (serverId == getTransientServerId());
    } else if (configData.getPersistentServerIdInitialized()) {
      return (serverId == configData.getPersistentServerId());
    } else {
      return false;
    }
  }

  /*************************************************************************
   *  The following public methods are for ORB shutdown.
   *************************************************************************/

  private String getHostName(String host)
      throws java.net.UnknownHostException {
    return InetAddress.getByName(host).getHostAddress();
  }

    /* keeping a copy of the getLocalHostName so that it can only be called
     * internally and the unauthorized clients cannot have access to the
     * localHost information, originally, the above code was calling
     * getLocalHostName from Connection.java.  If the hostname is cached in
     * Connection.java, then
     * it is a security hole, since any unauthorized client has access to
     * the host information.  With this change it is used internally so the
     * security problem is resolved.  Also in Connection.java, the
     * getLocalHost() implementation has changed to always call the
     * InetAddress.getLocalHost().getHostAddress()
     * The above mentioned method has been removed from the connection class
     */

  private static String localHostString = null;

  private synchronized String getLocalHostName() {
    if (localHostString == null) {
      try {
        localHostString = InetAddress.getLocalHost().getHostAddress();
      } catch (Exception ex) {
        throw wrapper.getLocalHostFailed(ex);
      }
    }
    return localHostString;
  }

  /******************************************************************************
   *  The following public methods are for ORB shutdown.
   *
   ******************************************************************************/

  /**
   * This method always returns false because the ORB never needs the
   * main thread to do work.
   */
  public synchronized boolean work_pending() {
    checkShutdownState();
    throw wrapper.genericNoImpl();
  }

  /**
   * This method does nothing. It is not required by the spec to do anything!
   */
  public synchronized void perform_work() {
    checkShutdownState();
    throw wrapper.genericNoImpl();
  }

  public synchronized void set_delegate(java.lang.Object servant) {
    checkShutdownState();

    POAFactory poaFactory = getPOAFactory();
    if (poaFactory != null) {
      ((org.omg.PortableServer.Servant) servant)
          ._set_delegate(poaFactory.getDelegateImpl());
    } else {
      throw wrapper.noPoa();
    }
  }

  ////////////////////////////////////////////////////
  //
  // pept.broker.Broker
  //

  public ClientInvocationInfo createOrIncrementInvocationInfo() {
    synchronized (this) {
      checkShutdownState();
    }
    StackImpl invocationInfoStack =
        (StackImpl) clientInvocationInfoStack.get();
    ClientInvocationInfo clientInvocationInfo = null;
    if (!invocationInfoStack.empty()) {
      clientInvocationInfo =
          (ClientInvocationInfo) invocationInfoStack.peek();
    }
    if ((clientInvocationInfo == null) ||
        (!clientInvocationInfo.isRetryInvocation())) {
      // This is a new call - not a retry.
      clientInvocationInfo = new CorbaInvocationInfo(this);
      startingDispatch();
      invocationInfoStack.push(clientInvocationInfo);
    }
    // Reset retry so recursive calls will get a new info object.
    clientInvocationInfo.setIsRetryInvocation(false);
    clientInvocationInfo.incrementEntryCount();
    return clientInvocationInfo;
  }

  public void releaseOrDecrementInvocationInfo() {
    synchronized (this) {
      checkShutdownState();
    }
    int entryCount = -1;
    ClientInvocationInfo clientInvocationInfo = null;
    StackImpl invocationInfoStack =
        (StackImpl) clientInvocationInfoStack.get();
    if (!invocationInfoStack.empty()) {
      clientInvocationInfo =
          (ClientInvocationInfo) invocationInfoStack.peek();
    } else {
      throw wrapper.invocationInfoStackEmpty();
    }
    clientInvocationInfo.decrementEntryCount();
    entryCount = clientInvocationInfo.getEntryCount();
    if (clientInvocationInfo.getEntryCount() == 0) {
      // 6763340: don't pop if this is a retry!
      if (!clientInvocationInfo.isRetryInvocation()) {
        invocationInfoStack.pop();
      }
      finishedDispatch();
    }
  }

  public ClientInvocationInfo getInvocationInfo() {
    synchronized (this) {
      checkShutdownState();
    }
    StackImpl invocationInfoStack =
        (StackImpl) clientInvocationInfoStack.get();
    return (ClientInvocationInfo) invocationInfoStack.peek();
  }

  ////////////////////////////////////////////////////
  //
  //
  //

  private Object clientDelegateFactoryAccessorLock = new Object();

  public void setClientDelegateFactory(ClientDelegateFactory factory) {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (clientDelegateFactoryAccessorLock) {
      clientDelegateFactory = factory;
    }
  }

  public ClientDelegateFactory getClientDelegateFactory() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (clientDelegateFactoryAccessorLock) {
      return clientDelegateFactory;
    }
  }

  private Object corbaContactInfoListFactoryAccessLock = new Object();

  public void setCorbaContactInfoListFactory(CorbaContactInfoListFactory factory) {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (corbaContactInfoListFactoryAccessLock) {
      corbaContactInfoListFactory = factory;
    }
  }

  public synchronized CorbaContactInfoListFactory getCorbaContactInfoListFactory() {
    checkShutdownState();
    return corbaContactInfoListFactory;
  }

  /**
   * Set the resolver used in this ORB.  This resolver will be used for list_initial_services
   * and resolve_initial_references.
   */
  public void setResolver(Resolver resolver) {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (resolverLock) {
      this.resolver = resolver;
    }
  }

  /**
   * Get the resolver used in this ORB.  This resolver will be used for list_initial_services
   * and resolve_initial_references.
   */
  public Resolver getResolver() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (resolverLock) {
      return resolver;
    }
  }

  /**
   * Set the LocalResolver used in this ORB.  This LocalResolver is used for
   * register_initial_reference only.
   */
  public void setLocalResolver(LocalResolver resolver) {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (resolverLock) {
      this.localResolver = resolver;
    }
  }

  /**
   * Get the LocalResolver used in this ORB.  This LocalResolver is used for
   * register_initial_reference only.
   */
  public LocalResolver getLocalResolver() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (resolverLock) {
      return localResolver;
    }
  }

  /**
   * Set the operation used in string_to_object calls.  The Operation must expect a
   * String and return an org.omg.CORBA.Object.
   */
  public void setURLOperation(Operation stringToObject) {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (urlOperationLock) {
      urlOperation = stringToObject;
    }
  }

  /**
   * Get the operation used in string_to_object calls.  The Operation must expect a
   * String and return an org.omg.CORBA.Object.
   */
  public Operation getURLOperation() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (urlOperationLock) {
      return urlOperation;
    }
  }

  public void setINSDelegate(CorbaServerRequestDispatcher sdel) {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (resolverLock) {
      insNamingDelegate = sdel;
    }
  }

  public TaggedComponentFactoryFinder getTaggedComponentFactoryFinder() {
    synchronized (this) {
      checkShutdownState();
    }
    return taggedComponentFactoryFinder;
  }

  public IdentifiableFactoryFinder getTaggedProfileFactoryFinder() {
    synchronized (this) {
      checkShutdownState();
    }
    return taggedProfileFactoryFinder;
  }

  public IdentifiableFactoryFinder getTaggedProfileTemplateFactoryFinder() {
    synchronized (this) {
      checkShutdownState();
    }
    return taggedProfileTemplateFactoryFinder;
  }

  private Object objectKeyFactoryAccessLock = new Object();

  public ObjectKeyFactory getObjectKeyFactory() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (objectKeyFactoryAccessLock) {
      return objectKeyFactory;
    }
  }

  public void setObjectKeyFactory(ObjectKeyFactory factory) {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (objectKeyFactoryAccessLock) {
      objectKeyFactory = factory;
    }
  }

  private Object transportManagerAccessorLock = new Object();

  public TransportManager getTransportManager() {
    synchronized (transportManagerAccessorLock) {
      if (transportManager == null) {
        transportManager = new CorbaTransportManagerImpl(this);
      }
      return transportManager;
    }
  }

  public CorbaTransportManager getCorbaTransportManager() {
    return (CorbaTransportManager) getTransportManager();
  }

  private Object legacyServerSocketManagerAccessLock = new Object();

  public LegacyServerSocketManager getLegacyServerSocketManager() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (legacyServerSocketManagerAccessLock) {
      if (legacyServerSocketManager == null) {
        legacyServerSocketManager = new LegacyServerSocketManagerImpl(this);
      }
      return legacyServerSocketManager;
    }
  }

  private Object threadPoolManagerAccessLock = new Object();

  public void setThreadPoolManager(ThreadPoolManager mgr) {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (threadPoolManagerAccessLock) {
      threadpoolMgr = mgr;
    }
  }

  public ThreadPoolManager getThreadPoolManager() {
    synchronized (this) {
      checkShutdownState();
    }
    synchronized (threadPoolManagerAccessLock) {
      if (threadpoolMgr == null) {
        threadpoolMgr = new ThreadPoolManagerImpl();
        orbOwnsThreadPoolManager = true;
      }
      return threadpoolMgr;
    }
  }

  public CopierManager getCopierManager() {
    synchronized (this) {
      checkShutdownState();
    }
    return copierManager;
  }
} // Class ORBImpl

////////////////////////////////////////////////////////////////////////
/// Helper class for a Synchronization Variable
////////////////////////////////////////////////////////////////////////

class SynchVariable {

  // Synchronization Variable
  public boolean _flag;

  // Constructor
  SynchVariable() {
    _flag = false;
  }

  // set Flag to true
  public void set() {
    _flag = true;
  }

  // get value
  public boolean value() {
    return _flag;
  }

  // reset Flag to true
  public void reset() {
    _flag = false;
  }
}

// End of file.
